package com.zhny.aiot.rtu.dir.plugin;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableMap;
import com.zhny.aiot.plugin.ICenterFacilities;
import com.zhny.aiot.plugin.IDeviceFactory;
import com.zhny.aiot.plugin.core.model.IRequestMessage;
import com.zhny.aiot.plugin.core.utils.MessageUtils;
import com.zhny.aiot.plugin.modbus.ModemEngine;
import com.zhny.aiot.plugin.modbus.device.ModemConfig;
import com.zhny.aiot.plugin.modbus.device.ModemDevice;
import com.zhny.aiot.plugin.modbus.device.modbus.ModbusCommandParam;
import com.zhny.aiot.plugin.modbus.handler.model.ModemRequestMessage;
import com.zhny.aiot.plugin.modbus.handler.model.ModemResponseMessage;
import com.zhny.aiot.plugin.model.DeviceEntity;
import com.zhny.aiot.plugin.model.MessageEntry;
import com.zhny.aiot.plugin.model.MessageType;
import com.zhny.aiot.plugin.model.TaskEntity;
import com.zhny.aiot.rtu.dir.plugin.model.RTUDIRStoreEntry;
import com.zhny.aiot.rtu.dir.plugin.model.ValueParam;
import org.pf4j.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;

public class RTUDIRDevice extends ModemDevice<RTUDIRStoreEntry> {
    private static final Logger logger = LoggerFactory.getLogger(RTUDIRDevice.class);
    private final Map<String, ModbusCommandParam> CommandOperations;
    public RTUDIRDevice(ModemEngine engine, IDeviceFactory<ModemConfig> factory, ICenterFacilities centerFacilities, DeviceEntity entity) {
        super(engine, factory, centerFacilities, entity);
        CommandOperations=new ImmutableMap.Builder<String, ModbusCommandParam> ()
                .put ("open", ModbusCommandParam.valueOf ((short) 6, 10, 0x0065))
                .put ("close", ModbusCommandParam.valueOf ((short) 6, 10, 0x0066))
                .put ("stop", ModbusCommandParam.valueOf ((short) 6, 10, 0x0068))
                .put ("value", ModbusCommandParam.valueOf ((short) 6, 10, 1))
                .put ("query", ModbusCommandParam.valueOf ((short) 3, 3, 1))
                .build ();
    }

    @Override
    public void onDecoder(ModemResponseMessage modemResponseMessage) {
        logger.info ("zhny rtu dir decoder start");
        MessageEntry entry=MessageUtils.createMessageEntry (this.getId ());
        entry.setType (MessageType.RESULT);
        entry.getProperties ().put ("gprs", this.getConfig ().getGprsNo ());
        entry.getProperties ().put ("address", this.getConfig ().getAddress ());

        int isRecord=modemResponseMessage.getData ().readByte ();
        int status=modemResponseMessage.getData ().readByte ();
        String value="";
        if(modemResponseMessage.getFunction () == 0x06) {
            value=onStatusConvert (status);
        }else if(modemResponseMessage.getFunction () == 0x03) {
            value=onQueryConvert (status);
        }else {
            entry.setType (MessageType.ERROR);
            nofity (entry);
        }
        RTUDIRStoreEntry storeEntry=new RTUDIRStoreEntry ();
        logger.info ("rtu dir：{} 获取值:{}", this.getDeviceEntity ().getName (), value);
        storeEntry.setStatus (value);
        entry.setData (storeEntry);
        nofity (entry);
        saveReal (storeEntry);
        save (storeEntry);
    }

    private String onQueryConvert(int status) {
        return status == 0 ? "设备未接" :
                status == 1 ? "全开" :
                status == 2 ? "全关" :"悬停" ;
    }

    private String onStatusConvert(int status) {
        return status == 101 ? "全开" :
                status == 102 ? "全关" :
                  status == 104 ? "停止" : String.valueOf (status);
    }

    @Override
    protected IRequestMessage getCommand(TaskEntity taskEntity) {
        logger.info ("zhny rtu dir encode command !");
        MessageEntry entry=MessageUtils.createMessageEntry (this.getId ());
        entry.getProperties ().put ("task_name", taskEntity.getMethodName ());
        entry.setType (MessageType.OPERATION);
        ModbusCommandParam command=CommandOperations.get (taskEntity.getMethodName ());
        if(command == null) {
            entry.setType (MessageType.ERROR);
            entry.setData (String.format ("factory[%s] no support command [%s]", getTypeId (), taskEntity.getMethodName ()));
            this.nofity (entry);
            return null;
        }
        String methodName = taskEntity.getMethodName ();
        logger.info ("zhny rtu dir {} command !",methodName);
        if(methodName.contains ("value")){
            if(!StringUtils.isNullOrEmpty(taskEntity.getParams ())){
                ObjectMapper mapper = new ObjectMapper();
                mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
                try{
                    ValueParam param = mapper.readValue (taskEntity.getParams (), ValueParam.class);
                    command.setDataSize (param.getValue ());
                }catch (Exception e){
                    logger.error ("Parse param error !");
                    return  null;
                }
            }
        }
        logger.info ("zhny rtu dir encode o:{}-r:{}-d:{}!",command.getOper (),command.getRegAdress (),command.getDataSize ());
        return new ModemRequestMessage (
                Integer.valueOf (this.getConfig ().getAddress ()),
                command.getOper (),
                command.getRegAdress (),
                command.getDataSize ()
        );
    }

    @Override
    protected void disposable() {

    }
}
